<template>
  <div>
    <el-input v-model="selected" placeholder="请选择文件夹" @click="selectDir"></el-input>
    <el-button type="primary" @click="getAllFiles" v-loading.fullscreen.lock="searchLoading"
      :element-loading-text="`已经获取 0 个文件`">查询单文件内重复文件</el-button>
    <el-button type="primary" @click=caculateSha1>计算sha1</el-button>
    <el-button type="danger" @click="openDialog">删除文件</el-button>
    <el-button type="primary" @click="getDatas" v-loading.fullscreen.lock="searchLoading"
      :element-loading-text="`已经获取 0 个文件`">查询多文件夹内重复文件</el-button>
    <el-progress :percentage="progressPercent" text-inside :stroke-width="25" />
  </div>
  <div style="height: calc(100% - 89px);">
    <el-auto-resizer style="width: 100%;">
      <template #default="{ height, width }">
        <el-table-v2 :columns="columns" :data="tableData" :height="height" :width="width" expand-column-key="filename"
          row-key="leftid" :row-class="RowClass" :default-expanded-row-keys="defaultExpandedRowKeys"
          v-loading.lock="tableLoading">
          <template #row="props">
            <Row v-bind="props" />
          </template>
        </el-table-v2>
      </template>
    </el-auto-resizer>
  </div>
  <el-dialog v-model="dialogVisible" title="删除文件" @keyup.enter="deleteFiles">
    <el-table :data="files">
      <el-table-column label="路径" prop="path"></el-table-column>
    </el-table>
    <template #footer>
      <span class="dialog-footer">
        <el-button @click="dialogVisible = false">取消</el-button>
        <el-button type="primary" @click="deleteFiles">确认</el-button>
      </span>
    </template>
  </el-dialog>
</template>

<script setup lang="tsx">
import { Ref, cloneVNode, ref } from 'vue';
import { open } from '@tauri-apps/plugin-dialog'
import { invoke } from "@tauri-apps/api/core";
import { CheckboxValueType, ElCheckbox } from 'element-plus';

const selected = ref('')
const selectDir = () => {
  open({
    directory: true
  }).then((r: any) => {
    selected.value = r
  })
}

const columns: any = [
  { key: "id", dataKey: "leftid", title: "序号", width: 100, align: "center" },
  { key: "sha1", dataKey: "leftsha1", title: "SHA1", width: 400, align: "center" },
  { key: "modified_time", dataKey: "leftmodified_time", title: "修改日期", width: 200, align: "center" },
  { key: "created_time", dataKey: "leftcreated_time", title: "创建日期", width: 200, align: "center" },
  { key: "filename", dataKey: "leftfilename", title: "路径", width: 400, align: "right" },
  { key: "colortype", dataKey: "leftcolortype", title: "颜色类型", width: 100, align: "center" },
  { key: "exif", dataKey: "leftexif", title: "exif信息数", width: 100, align: "center" },
  { key: "len", dataKey: "leftlen", title: "文件大小", width: 100, align: "right" },
  {
    key: "select", width: 50, align: "center",
    cellRenderer: ({ rowData }: any) => {
      const onChange = (value: CheckboxValueType) => {
        rowData.leftchecked = value
        if (rowData.sha1 == undefined) {
          rowData.children.map((children: any) => children.leftchecked = value)
        }
      }
      return <ElCheckbox modelValue={rowData.leftchecked} onChange={onChange} />
    },
    headerCellRenderer: () => {
      const _data: any = tableData.value
      const onChange = (value: CheckboxValueType) =>
      (tableData.value = _data.map((row: any) => {
        row.leftchecked = value
        return row
      }))
      const allSelected = _data.every((row: any) => row.leftchecked)
      const containsChecked = _data.some((row: any) => row.leftchecked)
      return <ElCheckbox modelValue={allSelected} indeterminate={containsChecked && !allSelected} onChange={onChange} />
    }
  },
  {
    key: "select", width: 50, align: "center",
    cellRenderer: ({ rowData }: any) => {
      const onChange = (value: CheckboxValueType) => {
        rowData.rightchecked = value
        if (rowData.sha1 == undefined) {
          rowData.children.map((children: any) => children.rightchecked = value)
        }
      }
      return <ElCheckbox modelValue={rowData.rightchecked} onChange={onChange} />
    },
    headerCellRenderer: () => {
      const _data: any = tableData.value
      const onChange = (value: CheckboxValueType) =>
      (tableData.value = _data.map((row: any) => {
        row.rightchecked = value
        return row
      }))
      const allSelected = _data.every((row: any) => row.rightchecked)
      const containsChecked = _data.some((row: any) => row.rightchecked)
      return <ElCheckbox modelValue={allSelected} indeterminate={containsChecked && !allSelected} onChange={onChange} />
    }
  },
  { key: "len", dataKey: "rightlen", title: "文件大小", width: 100 },
  { key: "exif", dataKey: "rightexif", title: "exif信息数", width: 100, align: "center" },
  { key: "colortype", dataKey: "rightcolortype", title: "颜色类型", width: 100, align: "center" },
  { key: "filename", dataKey: "rightfilename", title: "路径", width: 400 },
  { key: "created_time", dataKey: "rightcreated_time", title: "创建日期", width: 200, align: "center" },
  { key: "modified_time", dataKey: "rightmodified_time", title: "修改日期", width: 200, align: "center" },
  { key: "sha1", dataKey: "rightsha1", title: "SHA1", width: 400, align: "center" },
  { key: "id", dataKey: "rightid", title: "序号", width: 100, align: "center" }
]

const tableData: Ref<any[]> = ref([])

let repeatedCount: any = {}

let searchLoading = ref(false)

const getAllFiles = async () => {
  //如果未选择目录，则提示选择目录
  if (selected.value == "") {
    return
  }
  // 加载
  searchLoading.value = true
  let count = 0
  let loadingTextHtml = await Promise.resolve().then(() => {
    return document.querySelector(".el-loading-text")
  })
  let timer = setInterval(() => {
    invoke('get_walkfile_count').then((res: any) => {
      count = res
      loadingTextHtml!.innerHTML = `已经获取 ${count} 个文件`
    })
  }, 1000)

  const res: string = await invoke("get_datas", { path: selected.value })

  const resDatas = JSON.parse(res)

  tableData.value = []

  for (let i = 0; i < resDatas.length; i++) {
    const curFileInfo = resDatas[i];

    curFileInfo.leftid = curFileInfo.id
    curFileInfo.leftsha1 = curFileInfo.sha1
    curFileInfo.leftmodified_time = curFileInfo.modified_time
    curFileInfo.leftcreated_time = curFileInfo.created_time
    curFileInfo.leftfilename = curFileInfo.path.split('\\').pop()
    curFileInfo.leftlen = curFileInfo.len
    curFileInfo.leftpath = curFileInfo.path
    curFileInfo.leftcolortype = curFileInfo.colortype
    curFileInfo.leftexif = curFileInfo.exif

    tableData.value.push(curFileInfo)
  }

  clearInterval(timer)
  searchLoading.value = false
}

const getSingleDirDatas = async () => {
  if (selected.value == "") {
    return
  }
  searchLoading.value = true
  let count = 0
  let loadingTextHtml = await Promise.resolve().then(() => {
    return document.querySelector(".el-loading-text")
  })
  let timer = setInterval(() => {
    invoke('get_walkfile_count').then((res: any) => {
      count = res
      loadingTextHtml!.innerHTML = `已经获取 ${count} 个文件`
    })
  }, 1000)

  const res: string = await invoke("get_datas", { path: selected.value })
  const resDatas = JSON.parse(res)

  tableData.value = []
  repeatedCount = {}
  for (let i = 0; i < resDatas.length; i++) {
    const fileInfo = resDatas[i];
    if (fileInfo.sha1 != null) {
      if (repeatedCount[fileInfo.sha1] == undefined) {
        repeatedCount[fileInfo.sha1] = 1
      } else {
        //已经有相同的sha1，该文件重复
        let pre = resDatas[i - 1].path.split('\\')
        pre.pop()
        let cur = fileInfo.path.split('\\')
        cur.pop()

        if (JSON.stringify(cur) == JSON.stringify(pre)) {
          fileInfo.leftchecked = true
        }
        repeatedCount[fileInfo.sha1]++
      }
    }
  }

  for (let i = 0; i < resDatas.length; i++) {
    const curFileInfo = resDatas[i];

    if (repeatedCount[curFileInfo.sha1] > 1) {

      curFileInfo.leftid = curFileInfo.id
      curFileInfo.leftsha1 = curFileInfo.sha1
      curFileInfo.leftmodified_time = curFileInfo.modified_time
      curFileInfo.leftcreated_time = curFileInfo.created_time
      curFileInfo.leftfilename = curFileInfo.path.split('\\').pop()
      curFileInfo.leftlen = curFileInfo.len
      curFileInfo.leftpath = curFileInfo.path
      curFileInfo.leftcolortype = curFileInfo.colortype
      curFileInfo.leftexif = curFileInfo.exif

      tableData.value.push(curFileInfo)
    }
  }

  clearInterval(timer)
  searchLoading.value = false
}

const getDatas = async () => {
  if (selected.value == "") {
    return
  }
  searchLoading.value = true
  let count = 0

  let loadingTextHtml = await Promise.resolve().then(() => {
    return document.querySelector(".el-loading-text")
  })
  let timer = setInterval(() => {
    invoke('get_walkfile_count').then((res: any) => {
      count = res
      loadingTextHtml!.innerHTML = `已经获取 ${count} 个文件`
    })
  }, 1000)

  const res: string = await invoke("get_datas", { path: selected.value })
  const resDatas = JSON.parse(res)

  tableData.value = []
  dirPair = []
  repeatedCount = {}
  for (let i = 0; i < resDatas.length; i++) {
    const fileInfo = resDatas[i];
    if (fileInfo.sha1 != null) {
      if (repeatedCount[fileInfo.sha1] == undefined) {
        repeatedCount[fileInfo.sha1] = 1
      } else {
        //已经有相同的sha1，该文件重复
        repeatedCount[fileInfo.sha1]++
      }
    }
  }

  for (let i = 0; i < resDatas.length; i++) {
    const curFileInfo = resDatas[i];
    const nexFileInfo = resDatas[i + 1]

    if (nexFileInfo == undefined) {
      break
    }

    if (repeatedCount[curFileInfo.sha1] > 1) {
      if (repeatedCount[curFileInfo.sha1] % 2 == 0) {
        new FileInfo(curFileInfo, nexFileInfo).walk()
        i++
      } else {
        if (curFileInfo.sha1 == nexFileInfo.sha1) {
          new FileInfo(curFileInfo, nexFileInfo).walk()
          i++
        }
      }
    }
  }

  clearInterval(timer)
  searchLoading.value = false
}

const RowClass = ({ rowData }: any) => {

  if (rowData.leftsha1 == undefined) {
    return 'isDir'
  } else {
    if (repeatedCount[rowData.leftsha1] > 1) {
      if (rowData.leftcolortype == rowData.rightcolortype && rowData.leftexif == rowData.rightexif && rowData.leftlen == rowData.rightlen) {
        return 'isSame'
      } else {
        return 'isRepeated'
      }
    }
  }
}

const leftcolSpanIndex = 4
const rightcolSpanIndex = 13

const Row = ({ rowData, cells }: any) => {
  if (rowData.leftpath == undefined) {
    const colSpan = 5
    let width = Number.parseInt(cells[leftcolSpanIndex].props.style.width)
    for (let i = 1; i < colSpan; i++) {
      width += Number.parseInt(cells[leftcolSpanIndex - i].props.style.width)
      cells[leftcolSpanIndex - i] = null
    }
    const style = {
      ...cells[leftcolSpanIndex].props.style,
      width: `${width}px`,
    }
    cells[leftcolSpanIndex] = cloneVNode(cells[leftcolSpanIndex], { style })
  }

  if (rowData.rightpath == undefined) {
    const colSpan = 5
    let width = Number.parseInt(cells[rightcolSpanIndex].props.style.width)
    for (let i = 1; i < colSpan; i++) {
      width += Number.parseInt(cells[rightcolSpanIndex + i].props.style.width)
      cells[rightcolSpanIndex + i] = null
    }
    const style = {
      ...cells[rightcolSpanIndex].props.style,
      width: `${width}px`,
    }
    cells[rightcolSpanIndex] = cloneVNode(cells[rightcolSpanIndex], { style })
  }

  return cells
}

const defaultExpandedRowKeys: Ref<any[]> = ref([])

let progressPercent = ref(0)
let tableLoading = ref(false)
const caculateSha1 = async () => {
  tableLoading.value = true
  progressPercent.value = 0
  let timer = setInterval(() => {
    invoke('get_progress_percent').then((res: any) => {
      progressPercent.value = res
    })
  }, 1000)
  await invoke('caculate_sha1', { path: selected.value })
  clearInterval(timer)

  invoke('get_progress_percent').then((res: any) => {
    progressPercent.value = res
  })

  tableLoading.value = false
  getSingleDirDatas()
}

const dialogVisible = ref(false)
const files: Ref<any[]> = ref([])

const openDialog = () => {
  files.value = []
  const getCheckedFilePath = (tableData: any) => {
    for (let i = 0; i < tableData.length; i++) {
      const fileInfos = tableData[i];
      if (fileInfos.children) {
        for (let j = 0; j < fileInfos.children.length; j++) {
          const fileInfo = fileInfos.children[j];
          if (fileInfo.leftchecked) {
            files.value.push({ path: fileInfo.leftpath })
          }
          if (fileInfo.rightchecked) {
            files.value.push({ path: fileInfo.rightpath })
          }
        }
      } else {
        if (fileInfos.leftchecked) {
          files.value.push({ path: fileInfos.leftpath })
        }
        if (fileInfos.rightchecked) {
          files.value.push({ path: fileInfos.rightpath })
        }
      }
    }
  }
  getCheckedFilePath(tableData.value)
  dialogVisible.value = true
}

const deleteFiles = async () => {
  dialogVisible.value = false
  tableLoading.value = true

  let vecPaths = []
  for (let i = 0; i < files.value.length; i++) {
    const element = files.value[i];
    vecPaths.push(element.path)
  }
  const res = await invoke('delete_files', { vecPaths })
  alert(res)
  tableLoading.value = false
  getDatas()
}

let dirPair: any[] = []

class FileInfo {
  leftFile
  rightFile

  constructor(preFileInfo: any, nexFileInfo: any) {
    this.leftFile = preFileInfo
    this.rightFile = nexFileInfo
  }
  walk() {
    let pathBuf = this.leftFile.path.split('\\')
    let filename = pathBuf.pop()
    let leftdir = pathBuf.join('\\')

    let rightpathBuf = this.rightFile.path.split('\\')
    let rightfilename = rightpathBuf.pop()
    let rightdir = rightpathBuf.join('\\')

    //如果文件夹不在默认展开，则添入
    if (!defaultExpandedRowKeys.value.find((x: any) => x == leftdir)) {
      defaultExpandedRowKeys.value.push(leftdir)
    }
    //如果文件夹不在默认展开，则添入
    if (!defaultExpandedRowKeys.value.find((x: any) => x == rightdir)) {
      defaultExpandedRowKeys.value.push(rightdir)
    }

    let pairdir = dirPair.find(x => x[leftdir] != undefined && x[rightdir] != undefined)

    if (pairdir == undefined) {
      //如果是文件夹
      let length = tableData.value.push({ leftid: tableData.value.length, leftfilename: leftdir, rightfilename: rightdir, children: [] })

      let obj: any = {}
      obj[leftdir] = length - 1
      obj[rightdir] = length - 1

      dirPair.push(obj)
      pairdir = obj
    }

    let index = pairdir[leftdir]

    tableData.value[index].children.push({
      leftid: this.leftFile.id,
      leftlen: this.leftFile.len,
      leftcreated_time: this.leftFile.created_time,
      leftmodified_time: this.leftFile.modified_time,
      leftpath: this.leftFile.path,
      leftsha1: this.leftFile.sha1,
      leftchecked: this.leftFile.checked,
      leftfilename: filename,
      leftcolortype: this.leftFile.colortype,
      leftexif: this.leftFile.exif,

      rightid: this.rightFile.id,
      rightlen: this.rightFile.len,
      rightcreated_time: this.rightFile.created_time,
      rightmodified_time: this.rightFile.modified_time,
      rightpath: this.rightFile.path,
      rightsha1: this.rightFile.sha1,
      rightchecked: this.rightFile.checked,
      rightfilename: rightfilename,
      rightcolortype: this.rightFile.colortype,
      rightexif: this.rightFile.exif,

    })
  }
}

</script>

<style scoped>
:global(.el-table-v2 .isSame>div:nth-child(6)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isSame>div:nth-child(7)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isSame>div:nth-child(8)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isSame>div:nth-child(11)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isSame>div:nth-child(12)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isSame>div:nth-child(13)) {
  background-color: #f56c6c;
}
:global(.el-table-v2 .isSame>div:nth-child(2)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isSame>div:nth-child(17)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isRepeated>div:nth-child(2)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isRepeated>div:nth-child(17)) {
  background-color: #f56c6c;
}

:global(.el-table-v2 .isDir) {
  background-color: #ffe8a0;
}
</style>